#include "QueryParser.h"


QueryParser::QueryParser(){
	query_cmd=NULL;
	subquery_cmd=NULL;
	ql_name = "sparql";
	rq = NULL;
	rasq_world=NULL;

    /*
     *初始化查询变量
     */
    rasq_world = rasqal_new_world();
    if(!rasq_world || rasqal_world_open(rasq_world)) {
    	std::cout << "Can't Initial the rasqal world!" << std::endl;
    }
}
QueryParser::~QueryParser(){
    /*
     * 释放rasqal_world指针
     */
	rasqal_free_world(rasq_world);
	rasqal_free_query(rq);
}

void QueryParser::analyze(std::string whole_query_cmd){
	query_cmd = (char *)whole_query_cmd.c_str();
	rq = rasqal_new_query(rasq_world, (const char*)ql_name,NULL);
    if(!rq) {
      std::cout << "Failed to create rq!" << std::endl;
    }
    rasqal_query_prepare2(rq, (const unsigned char*)query_cmd, NULL);
    subquery_size = get_subquery_number(rq);
    std::cout << "====== The size of subquery is :"  << subquery_size  << " ======"<< std::endl;
    subquery_pattern= new int[subquery_size][4];
    subquery_return(rq,subquery_array,subquery_variable_array,subquery_pattern);//获取查询子语句及查询语句的样式
    /*
     * 打印子查询语句中的各个元素，目标是找出未知数的位置并用该未知数创建新表
     */
    std::cout << "====== The subquery is : ========" << std::endl;
    for(int i=0;i<subquery_size;i++){
    	std::cout << (*(subquery_variable_array+i))[0] << " "<< (*(subquery_variable_array+i))[1] << " "<< (*(subquery_variable_array+i))[2] << std::endl;
    }

    subquery_get_variables(rq,variable_size,variables);//获取目标变量的数目及目标变量的名称

    std::cout << "====== The variables size is:" << variable_size <<" ======" << std::endl;
    std::cout << "====== The variables is: ======" << std::endl;
    for(int i=0;i<variable_size; i++){
    	std::cout << variables[i] << std::endl;
    }

    std::cout << "====== The subquery pattern is: ======" << std::endl;
    for(int i=0;i<subquery_size;i++){
//    	std::cout << (*(subquery_pattern+i))[0] << (*(subquery_pattern+i))[1] << (*(subquery_pattern+i))[2] <<(*(subquery_pattern+i))[3] <<std::endl;
    	for(int j=0; j<3; j++){
    		std::string subquery;
    		subquery=((*(subquery_pattern+i))[j]==14)?"Var ":"Const ";
    		std::cout << subquery;
    	}
    	std::cout << std::endl;
    }
}

/**
 * rasqal_query_prepare:
 * @query: the #rasqal_query object
 * @query_string: the query string (or NULL)
 * @base_uri: base URI of query string (optional)
 *
 * Prepare a query - typically parse it.
 *
 * Some query languages may require a base URI to resolve any
 * relative URIs in the query string.  If this is not given,
 * the current directory in the filesystem is used as the base URI.
 *
 * The query string may be NULL in which case it is not parsed
 * and the query parts may be created by API calls such as
 * rasqal_query_add_source etc.
 *
 * Return value: non-0 on failure.
 **/
int QueryParser::rasqal_query_prepare2(rasqal_query* query,
                     const unsigned char *query_string,
                     raptor_uri *base_uri)
{
  int rc = 0;

//  RASQAL_ASSERT_OBJECT_POINTER_RETURN_VALUE(query, rasqal_query, 1);

  if(query->failed)
    return 1;

  if(query->prepared)
    return 0;
  query->prepared = 1;

  query->store_results = 0;

  if(query_string) {
    /* flex lexers require two NULs at the end of the lexed buffer.
     * Add them here instead of parser to allow resource cleanup on error.
     *
     * flex manual:
     *
     * Function: YY_BUFFER_STATE yy_scan_buffer (char *base, yy_size_t size)
     * which scans in place the buffer starting at `base', consisting of
     * `size' bytes, the last two bytes of which _must_ be
     * `YY_END_OF_BUFFER_CHAR' (ASCII NUL).  These last two bytes are not
     * scanned; thus, scanning consists of `base[0]' through
     * `base[size-2]', inclusive.
     */
    size_t len = strlen((const char*)query_string)+3; /* +3 for " \0\0" */
    unsigned char *query_string_copy = RASQAL_MALLOC(unsigned char*, len);
    if(!query_string_copy) {
      query->failed = 1;
      return 1;
    }
    memcpy(query_string_copy, query_string, len - 3);
    query_string_copy[len - 3] = ' ';
    query_string_copy[len - 2] = query_string_copy[len - 1] = '\0';
    query->query_string = query_string_copy;
    query->query_string_length = len;
  }

  if(base_uri)
    base_uri = raptor_uri_copy(base_uri);
  else {
    unsigned char *uri_string = raptor_uri_filename_to_uri_string("");
    base_uri = raptor_new_uri(query->world->raptor_world_ptr, uri_string);
    if(uri_string)
      raptor_free_memory(uri_string);
  }

  rasqal_query_set_base_uri(query, base_uri);
  query->locator.line = query->locator.column = query->locator.byte = -1;

  /* set evaluaton context with latest copies of query fields */
  query->eval_context->flags = query->compare_flags;
  rasqal_evaluation_context_set_base_uri(query->eval_context, query->base_uri);

  /* set random seed */
  if(1) {
    unsigned int seed;

    /* get seed either from user or system sources */
    if(query->user_set_rand)
      seed = (unsigned int)query->features[(int)RASQAL_FEATURE_RAND_SEED];
    else
      seed = rasqal_random_get_system_seed(query->world);

    rasqal_evaluation_context_set_rand_seed(query->eval_context, seed);
  }


  rc = query->factory->prepare(query);
  if(rc) {
    query->failed = 1;
    rc = 1;
  } else if(rasqal_query_prepare_common(query)) {
    query->failed = 1;
    rc = 1;
  }

  return rc;
}


/*
 * 获取问题子连接的数目
 */
int QueryParser::get_subquery_number(rasqal_query* rq){
	std::cout << rq->triples->size << std::endl;
	return  rq->triples->size;
}


int QueryParser::subquery_return(rasqal_query* rq, std::string *subquery, std::string (*subquery_element)[3],  int (*subquery_pattern)[4]){
	int rq_size;
	rq_size=get_subquery_number(rq);
	rasqal_triple  *t;
	rasqal_literal *tuple[3];
	std::string element[3]; //无尖括号
	std::string element_quot[3]; //有尖括号
	std::string subquery_cmd="SELECT ";
	const unsigned char*str;
	std::string quest="?";
	size_t len;

	for(int i=0;i<rq_size;i++){
		subquery_cmd="SELECT ";
		t=(rasqal_triple*)(rq->triples->sequence[rq->triples->start+i]);
		tuple[0]=t->subject;
		tuple[1]=t->predicate;
		tuple[2]=t->object;
		for(int j=0; j<3; j++){
			(*(subquery_pattern+i))[j]=tuple[j]->type;
			if(tuple[j]->type==RASQAL_LITERAL_VARIABLE){
				str = tuple[j]->value.variable->name;
				element_quot[j]= quest+ (const char*)str;
				subquery_cmd += element_quot[j]+' ';
				element[j]=quest+ (const char*)str;
				(*(subquery_element+i))[j]=(const char*)str;

			}
			else{
				str= raptor_uri_as_counted_string(tuple[j]->value.uri, &len) ;
				element_quot[j]= " <";
				element_quot[j]+= (const char*)str;
				element_quot[j]+= "> ";
				element[j] = (const char*)str;
				(*(subquery_element+i))[j]=(const char*)str;
			}
		}
		subquery_cmd += "WHERE {" + element_quot[0] +" " +element_quot[1] + " " + element_quot[2]+ "}";
		*(subquery+i) = subquery_cmd;

		subquery_to_Co(element,(subquery_pattern+i));
//		std::cout << " [ " << (*(subquery_pattern+i))[0] <<" "  << (*(subquery_pattern+i))[1] <<" " << (*(subquery_pattern+i))[2] << " " << (*(subquery_pattern+i))[3] << " ]" << std::endl;
	}
	return rq_size;
}


void QueryParser::subquery_get_variables(rasqal_query* rq,int& variable_size,std::string* variables){
    raptor_sequence *seq;
    int i;

    seq = rasqal_query_get_bound_variable_sequence(rq);
    if(seq && raptor_sequence_size(seq) > 0) {
//      fprintf(stdout, "query bound variables (%d): ",
//              raptor_sequence_size(seq));
      variable_size = raptor_sequence_size(seq);
      i = 0;
      while(1) {
        rasqal_variable* v = (rasqal_variable*)raptor_sequence_get_at(seq, i);
        if(!v)
          break;

//        if(i > 0)
//          fputs(", ", stdout);
//        roqet_query_write_variable2(stdout, v);
        *(variables+i)=(const char*)v->name;
        i++;
      }
      fputc('\n', stdout);
    }
    else{
    	variable_size=0;
    }
}

int QueryParser::subquery_to_Co(std::string element[3],int (*subquery_pattern)[4]){

	const int node_len =3;
	QString subjectQS;
	QString predicateQS;
	QString objectQS;
	QByteArray subjectQA;
	QByteArray predicateQA;
	QByteArray objectQA;
	short s_Co;
	short p_Co;
	short o_Co;
	short s_p_Co;
	short s_o_Co;
	short p_o_Co;
	short pos[7];
	short position;


	subjectQS = QString::fromLocal8Bit(element[0].c_str());
	subjectQA = QCryptographicHash::hash(subjectQS.toAscii(),QCryptographicHash::Sha1 );

	predicateQS = QString::fromLocal8Bit(element[1].c_str());
	predicateQA = QCryptographicHash::hash(predicateQS.toAscii(),QCryptographicHash::Sha1 );

	objectQS = QString::fromLocal8Bit(element[2].c_str());
	objectQA = QCryptographicHash::hash(objectQS.toAscii(),QCryptographicHash::Sha1 );

	s_Co = (uint)subjectQA[0] % node_len;   //S
	p_Co = (uint)predicateQA[0] % node_len; //p
	o_Co = (uint)objectQA[0] % node_len; 	//O

	// =================================================加入X、Y、Z相同轴长度处理=====================================================//
	QString subjectQS_y;
	QString predicateQS_y;
	QString objectQS_y;
	QByteArray subjectQA_y;
	QByteArray predicateQA_y;
	QByteArray objectQA_y;
	short s_Co_y;
	short p_Co_y;
	short o_Co_y;
	short s_p_Co_y;
	short s_o_Co_y;
	short p_o_Co_y;

	QString subjectQS_z;
	QString predicateQS_z;
	QString objectQS_z;
	QByteArray subjectQA_z;
	QByteArray predicateQA_z;
	QByteArray objectQA_z;
	short s_Co_z;
	short p_Co_z;
	short o_Co_z;
	short s_p_Co_z;
	short s_o_Co_z;
	short p_o_Co_z;

	subjectQS_y = QString::fromLocal8Bit((element[0]+" ").c_str());
	subjectQA_y = QCryptographicHash::hash(subjectQS_y.toAscii(),QCryptographicHash::Sha1 );

	predicateQS_y = QString::fromLocal8Bit((element[1]+" ").c_str());
	predicateQA_y = QCryptographicHash::hash(predicateQS_y.toAscii(),QCryptographicHash::Sha1 );

	objectQS_y = QString::fromLocal8Bit((element[2]+" ").c_str());
	objectQA_y = QCryptographicHash::hash(objectQS_y.toAscii(),QCryptographicHash::Sha1 );

	subjectQS_z = QString::fromLocal8Bit((element[0]+"  ").c_str());
	subjectQA_z = QCryptographicHash::hash(subjectQS_z.toAscii(),QCryptographicHash::Sha1 );

	predicateQS_z = QString::fromLocal8Bit((element[1]+"  ").c_str());
	predicateQA_z = QCryptographicHash::hash(predicateQS_z.toAscii(),QCryptographicHash::Sha1 );

	objectQS_z = QString::fromLocal8Bit((element[2]+"  ").c_str());
	objectQA_z = QCryptographicHash::hash(objectQS_z.toAscii(),QCryptographicHash::Sha1 );

	s_Co_y = (uint)subjectQA_y[0] % node_len;   //S_y
	p_Co_y = (uint)predicateQA_y[0] % node_len; //p_y
	o_Co_y = (uint)objectQA_y[0] % node_len; 	//O_y

	s_Co_z = (uint)subjectQA_z[0] % node_len;   //S_y
	p_Co_z = (uint)predicateQA_z[0] % node_len; //p_y
	o_Co_z = (uint)objectQA_z[0] % node_len; 	//O_y


	//===========================================End of 加入X、Y、Z相同轴长度处理=============================================//

	s_p_Co = (s_Co_z + p_Co_z) % node_len;		//s_z+p_z
	s_o_Co = (s_Co_y + o_Co_y) % node_len;		//s_y+o_y
	p_o_Co = (p_Co + o_Co) % node_len;		//p+o

	pos[0]=s_Co *9 + p_Co_y*3 + o_Co_z;  //[s,p,o]
	pos[1]=p_o_Co*9 + p_Co_y*3 + o_Co_z; //[p+o,p,o]
	pos[2]=s_Co *9 + s_o_Co*3 + o_Co_z; //[s,s+o,o]
	pos[3]=s_Co *9 + p_Co*3 + s_p_Co; //[s,p,s+p]
	pos[4]=s_Co *9 + s_Co_y*3 + s_Co_z; // [s,s,s]
	pos[5]=p_Co *9 + p_Co_y*3 + p_Co_z; // [p,p,p]
	pos[6]=o_Co *9 + o_Co_y*3 + o_Co_z; // [o,o,o]


	if((*subquery_pattern)[0]!= RASQAL_LITERAL_VARIABLE && (*subquery_pattern)[1]!= RASQAL_LITERAL_VARIABLE && (*subquery_pattern)[2]!= RASQAL_LITERAL_VARIABLE ){
		// s p o      =====> s p o
		std::cout << "s p o ==>"  << " coordinate= [" << s_Co << "," << p_Co_y << "," << o_Co_z <<"]"<<std::endl;
		position=pos[0];
	}
	else if((*subquery_pattern)[0]== RASQAL_LITERAL_VARIABLE && (*subquery_pattern)[1]!= RASQAL_LITERAL_VARIABLE && (*subquery_pattern)[2]!= RASQAL_LITERAL_VARIABLE ){
		// ?s p o       ====>  p+o , p  o
		std::cout << "?s p o ==> "  << " coordinate= [" << p_o_Co << "," << p_Co_y << "," << o_Co_z <<"]"<<  std::endl;
		position=pos[1];
	}
	else if((*subquery_pattern)[0]!= RASQAL_LITERAL_VARIABLE && (*subquery_pattern)[1]== RASQAL_LITERAL_VARIABLE && (*subquery_pattern)[2]!= RASQAL_LITERAL_VARIABLE ){
		// s ?p o       ====>  s , s+o  o
		std::cout << "s ?p o ==> " << " coordinate= [" << s_Co << "," << s_o_Co << "," << o_Co_z <<"]" << std::endl;
		position=pos[2];
	}
	else if((*subquery_pattern)[0]!= RASQAL_LITERAL_VARIABLE && (*subquery_pattern)[1]!= RASQAL_LITERAL_VARIABLE && (*subquery_pattern)[2]== RASQAL_LITERAL_VARIABLE ){
		// s p ?o       ====>  s , p  ,s+p
		std::cout << "s p ?o ==> " << " coordinate= [" << s_Co << "," << p_Co_y << "," << s_p_Co <<"]" << std::endl;
		position=pos[3];
	}
	else if((*subquery_pattern)[0]!= RASQAL_LITERAL_VARIABLE && (*subquery_pattern)[1]== RASQAL_LITERAL_VARIABLE && (*subquery_pattern)[2]== RASQAL_LITERAL_VARIABLE ){
		// s ?p ?o       ====>  s , s  ,s
		std::cout << "s ?p ?o ==> " << " coordinate= [" << s_Co << "," << s_Co_y << "," << s_Co_z <<"]" <<  std::endl;
		position=pos[4];
	}
	else if((*subquery_pattern)[0]== RASQAL_LITERAL_VARIABLE && (*subquery_pattern)[1]!= RASQAL_LITERAL_VARIABLE && (*subquery_pattern)[2]== RASQAL_LITERAL_VARIABLE ){
		// ?s p ?o       ====>  p , p;  p
		std::cout << "?s p ?o ==> " << " coordinate= [" << p_Co << "," << p_Co_y << "," << p_Co_z <<"]" <<  std::endl;
		position=pos[5];
	}
	else if((*subquery_pattern)[0]== RASQAL_LITERAL_VARIABLE && (*subquery_pattern)[1]== RASQAL_LITERAL_VARIABLE && (*subquery_pattern)[2]!= RASQAL_LITERAL_VARIABLE ){
		// ?s ?p o       ====>  o , o;  o
		std::cout << "?s ?p o ==> " << " coordinate= [" << o_Co << "," << o_Co_y << "," << o_Co_z <<"]" <<  std::endl;
		position=pos[6];
	}
	else{
		std::cout << "?s ?p ?o = " << std::endl;
		position=-1;
	}
	(*subquery_pattern)[3]=position;
	return position;
}

